/*
 * Copyright Iain Sproat, 2008
 * 
 *
 */
using System;
using System.Collections.Generic;

namespace FreeBase.Fluent
{
	/// <summary>
	/// This is used in a freebase query to indicate
	/// which properties should be returned
	/// </summary>
	public sealed class FBPlaceholder : FBInstruction
	{
		FBQuery _parentQuery = null;
		private NumberOfRecords _numberOfRecordsExpected = NumberOfRecords.Undefined;
		private bool _objectExpected = false;
		private bool _isReciprocal = false;
		
		internal FBPlaceholder( FBQuery returning )
		{
			if( returning == null )
				throw new ArgumentNullException("returning" );
			_parentQuery = returning;
		}
		
		#region Fluent Methods
		public FBQuery AllProperties
		{
			get{this.PropertyName = "*";
				return _parentQuery;}
		}
		
		public FBQuery Property( string propertyName )
		{
			if( string.IsNullOrEmpty( propertyName ) )
				throw new ArgumentNullException( propertyName );
			
			this.PropertyName = propertyName.ToLower();
			return _parentQuery;
		}
		
		public FBPlaceholder ManyRecordsFor
		{
			get{ this._numberOfRecordsExpected = NumberOfRecords.Many;
				return this;
			}
		}
		
		public FBPlaceholder ManyObjectsFor
		{
			get{ this._numberOfRecordsExpected = NumberOfRecords.Many;
				this._objectExpected = true;
				return this;
			}
		}
		
		public FBPlaceholder OneRecordFor
		{
			get{ this._numberOfRecordsExpected = NumberOfRecords.One;
				return this;
			}
		}
		
		public FBPlaceholder OneObjectFor
		{
			get{ this._numberOfRecordsExpected = NumberOfRecords.One;
				this._objectExpected = true;
				return this;
			}
		}
		
		public FBPlaceholder NoRecordsFor
		{
			get{ this._numberOfRecordsExpected = NumberOfRecords.None;
				return this;
			}
		}

		
		public FBQuery ReciprocalOf(string propertyName)
		{
			this.PropertyName = propertyName;
			this._numberOfRecordsExpected = NumberOfRecords.Many;
			this._isReciprocal = true;
			return this._parentQuery;
		}
		#endregion
		
		#region Fluent Helpers for common properties
		public FBQuery Name
		{
			get{
				return Property( "name" );
			}
		}
		
		public FBQuery Key
		{
			get{
				return Property( "key" );
			}
		}
		
		public FBQuery Id
		{
			get{
				return Property( "id" );
			}
		}
		public FBQuery Guid
		{
			get{
				return Property( "guid" );
			}
		}
		
		public FBQuery Type
		{
			get{
				return Property( "type" );
			}
		}
		
		public FBQuery Timestamp
		{
			get{
				return Property( "timestamp" );
			}
		}
		
		public FBQuery Creator
		{
			get{
				return Property( "creator" );
			}
		}
		
		public FBQuery Permission
		{
			get{
				return Property( "permission" );
			}
		}
		
		//FIXME
		public FBQuery IsUniqueProperty
		{
			get{
				return Property( "/type/property/unique" );
			}
		}
		
		public FBQuery MasterProperty
		{
			get{
				return Property( "master_property" );
			}
		}
		
		public FBQuery ReverseProperty
		{
			get{
				return Property( "reverse_property" );
			}
		}
		
		public FBQuery ExpectedType
		{
			get{
				return Property( "expected_type" );
			}
		}
		
		public FBQuery Unit
		{
			get{
				return Property( "unit" );
			}
		}
		
		public FBQuery Schema
		{
			get{
				return Property( "schema" );
			}
		}
		
		public FBQuery Unique
		{
			get{
				return Property( "unique" );
			}
		}

		public FBQuery Delegated
		{
			get{
				return Property( "delegated" );
			}
		}
		
		public FBQuery Enumeration
		{
			get{
				return Property( "enumeration" );
			}
		}
		
		public FBQuery Links
		{
			get{
				this._numberOfRecordsExpected = NumberOfRecords.Many;
				return Property( "links" );
			}
		}
		
		#endregion
		
		#region Internal methods for exposing private variables
		internal NumberOfRecords ShowManyRecords{
			get{ return this._numberOfRecordsExpected; }
		}
		
		internal bool ShowAsObject{
			get{ return this._objectExpected; }
		}
		
		internal bool IsReciprocal{
			get{ return this._isReciprocal; }
		}
		#endregion
	}
	public enum NumberOfRecords
	{
		None,
		One,
		Many,
		Undefined
	}
}
